//
//  Person.swift
//  运行时获取属性列表
//
//  Created by Summer on 2017/11/20.
//  Copyright © 2017年 Summer. All rights reserved.
//

import UIKit

// 需要加上@objcMembers 这么一个关键字。
// 类的属性前面需要加上@objc关键词或者类前面加上@objcMembers ，否则运行时访问不了类的属性
// 原因：在Swift 4中继承 NSObject 的 swift class 不再默认全部 bridge 到 OC，如果我们想要使用的话我们就需要在class前面加上@objcMembers 这么一个关键字。
// 引用: 在 swift 3 中除了手动添加 @objc 声明函数支持 OC 调用还有另外一种方式：继承 NSObject。class 继承了 NSObject 后，编译器就会默认给这个类中的所有函数都标记为 @objc ，支持 OC 调用。苹果在Swift 4 中苹果修改了自动添加 @objc 的逻辑：一个继承 NSObject 的 swift 类不再默认给所有函数添加 @objc。只在实现 OC 接口和重写 OC 方法时才自动给函数添加 @objc 标识。


@objcMembers class Person: NSObject {
    
    var name: String?
    
    var age: Int = 0  //方法一执行
    
    // 基本数据类型，在OC中没有可选，如果定义成可选，运行时同样获取不到，使用KVC就会崩溃
//    var age: Int? // 方法二执行
    
    
    // private var title: String?
    // private的属性，使用运行时，同样获取不到属性，（可以获取到ivar）同样会让KVC崩溃
    var title: String?
    
    class func propertyList() -> [String]{
        
        var count: UInt32 = 0
        // 1.获取类的属性列表,返回属性列表的数组,可选项
        let list = class_copyPropertyList(self, &count)
        print("属性个数:\(count)")
        
        /*            方法一            */
        // 2.遍历数组
        for i in 0..<Int(count) {
            //根据下标获取属性
            let pty = list?[i]
            //获取属性的名称<C语言字符串>
            //转换过程:Int8 -> Byte -> Char -> C语言字符串
            let cName = property_getName(pty!)
            //转换成String的字符串
            let name = String(utf8String: cName)
            print(name)
        }
        
        
        /*            方法二            */
        //遍历数组
//        for i in 0..<Int(count) {
//
//            guard let pty = list?[i],
//                let cName = property_getName(pty),
//            let name = String(utf8String: cName) else {
//                // 继续遍历下一个
//                continue
//            }
//
//            print(name)
//        }
        
        
        
        
        
        
        
        
        
        // 3.释放
        free(list) //释放list
        return []
    }

}
